using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Windows;
using MJB.UI.ContentEditor.Document;

namespace MJB.UI.ContentEditor.Document.Version1
{

    /// <summary>
    /// This class implements ISchemaReader for version1 of the content schema.
    /// </summary>
    [DocumentReaderHandler(DocumentConstants.VERSION1_NAMESPACE)]
    public class DocumentReaderVersion1 : DependencyObject, IDocumentReader
    {
        #region Member Variables

        /// <summary>
        /// This is the title of the document.
        /// </summary>
        private static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title",
            typeof(string),
            typeof(DocumentReaderVersion1),
            new PropertyMetadata(String.Empty));

        /// <summary>
        /// This is the description string.
        /// </summary>
        private static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register("Description",
            typeof(string),
            typeof(DocumentReaderVersion1),
            new PropertyMetadata(String.Empty));


        /// <summary>
        /// This is the FilePath string.
        /// </summary>
        private static readonly DependencyProperty FilePathProperty = DependencyProperty.Register("FilePath",
            typeof(string),
            typeof(DocumentReaderVersion1),
            new PropertyMetadata(String.Empty));

        /// <summary>
        /// This is the FilePath string.
        /// </summary>
        private static readonly DependencyProperty FileNameProperty = DependencyProperty.Register("FileName",
            typeof(string),
            typeof(DocumentReaderVersion1),
            new PropertyMetadata(String.Empty));

        /// <summary>
        /// This is the keywords string.
        /// </summary>
        private static readonly DependencyProperty KeywordsProperty = DependencyProperty.Register("Keywords",
            typeof(string),
            typeof(DocumentReaderVersion1),
            new PropertyMetadata(String.Empty));

        /// <summary>
        /// This is an array version of the section property of the content object.
        /// </summary>
        private static readonly DependencyProperty SectionsProperty = DependencyProperty.Register("Sections",
            typeof(ObservableCollection<ISection>),
            typeof(DocumentReaderVersion1));

        #endregion
        #region Constructor

        /// <summary>
        /// Creates a new schema reader.
        /// </summary>
        public DocumentReaderVersion1()
        {
            this.Sections = new ObservableCollection<ISection>();
        }

        #endregion
        #region ISchemaReader Members

        /// <summary>
        /// Gets / sets the title.
        /// </summary>
        public string Title
        {
            get
            {
                return (string)GetValue(TitleProperty);
            }
            set
            {
                SetValue(TitleProperty, value);
            }
        }

        /// <summary>
        /// Gets / sets the description.
        /// </summary>
        public string Description
        {
            get
            {
                return (string)GetValue(DescriptionProperty);
            }
            set
            {
                SetValue(DescriptionProperty, value);
            }
        }

        /// <summary>
        /// Gets sets the file path.
        /// </summary>
        public string FilePath
        {
            get
            {
                return (string)GetValue(FilePathProperty);
            }
            set
            {
                SetValue(FilePathProperty, value);
            }
        }

        /// <summary>
        /// Gets sets the file name.
        /// </summary>
        public string FileName
        {
            get
            {
                return (string)GetValue(FileNameProperty);
            }
            set
            {
                SetValue(FileNameProperty, value);
            }
        }

        /// <summary>
        /// Gets / sets the keywords.
        /// </summary>
        public string Keywords
        {
            get
            {
                return (string)GetValue(KeywordsProperty);
            }
            set
            {
                SetValue(KeywordsProperty, value);
            }
        }

        /// <summary>
        /// Returns version1.
        /// </summary>
        public string VersionNamespace
        {
            get
            {
                return DocumentConstants.VERSION1_NAMESPACE;
            }
        }

        /// <summary>
        /// Gets / sets the list of schema sections.
        /// </summary>
        public ObservableCollection<ISection> Sections
        {
            get
            {
                return (ObservableCollection<ISection>)GetValue(SectionsProperty);
            }
            set
            {
                SetValue(SectionsProperty, value);
            }
        }

        /// <summary>
        /// Creates a new section object.
        /// </summary>
        /// <returns></returns>
        public ISection CreateNewSection()
        {
            return new SectionVersion1();
        }

        /// <summary>
        /// Loads this content object from a file.
        /// </summary>
        /// <param name="textReader">The xml text reader to load from.</param>
        public void ReadXml(XmlReader reader)
        {
            // Clear this, in case we are reading again!
            this.Sections.Clear();

            reader.ReadStartElement("Content", DocumentConstants.VERSION1_NAMESPACE);
            reader.ReadStartElement("ContentProperties");

            this.Title = reader.ReadElementString("Title");
            this.Description = reader.ReadElementString("Description");
            this.Keywords = reader.ReadElementString("Keywords");

            reader.ReadEndElement();
            reader.ReadStartElement("Sections");

            // I've never done a do / while in my entire life...until now!
            do
            {
                // Read all of the sections.  This is in a while loop because 
                // if we have <Section>....</Section><Section>, then the cursor goes
                // directly to the second <Section> element right after we're done calling
                // ReadInnerXml.  Without the while loop, the next call to reader.Read() skips
                // over the next section!
                while(reader.NodeType == XmlNodeType.Element && reader.Name == "Section")
                {
                    // Create the section:
                    ISection section = CreateNewSection();

                    // Read the section title / last modified:
                    if(reader.MoveToFirstAttribute())
                    {
                        // Wow...another logical place to put 
                        // a do / while.  Never thought I'd see the day!
                        do
                        {
                            if(reader.Name == "Title")
                                section.SectionTitle = reader.Value;

                            else if(reader.Name == "LastModified")
                            {
                                section.LastModified = DateTime.Parse(reader.Value);
                                section.UsesLastModified = true;
                            }

                        }
                        while(reader.MoveToNextAttribute());

                        // Move the reader back to the element:
                        reader.MoveToElement();

                    }

                    section.SectionText = reader.ReadInnerXml();
                    this.Sections.Add(section);

                }

                if(reader.NodeType == XmlNodeType.EndElement && reader.Name == "Sections")
                    break;


            } while(reader.Read());

        }

        /// <summary>
        /// Writes the content to a file.
        /// </summary>
        /// <param name="writer"></param>
        public void WriteXml(XmlWriter writer)
        {
            writer.WriteStartDocument();
            writer.WriteStartElement("mjb", "Content", DocumentConstants.VERSION1_NAMESPACE);

            // Writes the content properties:
            writer.WriteStartElement("ContentProperties");
            writer.WriteElementString("Title", this.Title);
            writer.WriteElementString("Description", this.Description);
            writer.WriteElementString("Keywords", this.Keywords);
            writer.WriteEndElement();

            // Write the sections:
            writer.WriteStartElement("Sections");
            foreach(ISection section in this.Sections)
            {
                // Write the section element:
                writer.WriteStartElement("Section");

                // Write its attributes:
                writer.WriteAttributeString("Title", section.SectionTitle);
                if(section.UsesLastModified)
                {
                    StringBuilder dateTimeBuilder = new StringBuilder();
                    dateTimeBuilder.Append(section.LastModified.Year.ToString());
                    dateTimeBuilder.Append("-");
                    dateTimeBuilder.Append(section.LastModified.Month.ToString());
                    dateTimeBuilder.Append("-");
                    dateTimeBuilder.Append(section.LastModified.Day.ToString());
                    writer.WriteAttributeString("LastModified", dateTimeBuilder.ToString());
                }

                writer.WriteRaw(section.SectionText);
                writer.WriteEndElement();

            }

            // All done:
            writer.WriteEndElement();	// </Sections>
            writer.WriteEndElement();	// </mjb:Content>

        }

        /// <summary>
        /// Returns null (for now!)
        /// </summary>
        /// <returns></returns>
        public XmlSchema GetSchema()
        {
            return null;
        }

        #endregion
        #region Event Handlers
        #endregion

    }

}
